package net.chrisrichardson.ec2deployer.cluster

import net.chrisrichardson.ec2deployer.core.EC2Server
import net.chrisrichardson.ec2deployer.core.EC2
import groovy.mock.interceptor.MockFor
import net.chrisrichardson.ec2deployer.core.AWSProperties
import net.chrisrichardson.ec2deployer.core.EC2InstanceType


class MultipleInstancesTopologyTest extends GroovyTestCase {

    MockFor mockEc2
    MockFor mockEc2Server
    AWSProperties awsProperties
    ClusterSpec clusterSpec

    public void setUp() {
        mockEc2 = new MockFor(EC2)
        mockEc2Server = new MockFor(EC2Server)
        def props = new Properties()

        clusterSpec = new ClusterSpec()
                .tomcats(1)
                .slaves(1)
                .webApp('target/ptrack', "ptrack")
                .catalinaOptsBuilder({builder, databasePrivateDnsName ->})
                .schema("ptrack", ["ptrack": "ptrack"])
        clusterSpec.withJmeter()

        awsProperties = new AWSProperties(props)
    }

    public void testAllocateServers() {

        def allocatedServers = []

        5.times{mockEc2Server.demand.getAvailabilityZone { -> "newyork" }}

        1.times {
            mockEc2.demand.newServers {numberOfServers, instanceType, params ->
                // assertEquals 1, numberOfServers
                assertEquals EC2InstanceType.SMALL, instanceType
                assertEquals ([:], params) 
                if (numberOfServers < 1)
                    return []
                def servers = (1..numberOfServers).collect {new EC2Server()}
                allocatedServers.addAll(servers)
                servers
            }
        }
        5.times {
            mockEc2.demand.newServers {numberOfServers, instanceType, params ->
                // assertEquals 1, numberOfServers
                assertEquals EC2InstanceType.SMALL, instanceType
                assertEquals (["Placement.AvailabilityZone": "newyork"], params) 
                if (numberOfServers < 1)
                    return []
                def servers = (1..numberOfServers).collect {new EC2Server()}
                allocatedServers.addAll(servers)
                servers
            }
        }


        mockEc2Server.use {
            mockEc2.use {
                def ec2 = new EC2(awsProperties)

                def topology = new MultipleInstancesTopology()

                ClusterHosts servers = topology.allocateServers(ec2, clusterSpec, false)

                assertEquals allocatedServers[0], servers.databaseServer
                assertEquals allocatedServers[1..1], servers.mySqlSlaves
                assertEquals allocatedServers[2..2], servers.tomcats
                assertEquals allocatedServers[3], servers.apacheServer
                assertEquals allocatedServers[4], servers.jmeter

            }
        }
        assertEquals 5, allocatedServers.size()
    }

    public void testAllocateServersWithoutJmeter() {
        clusterSpec.runJmeter = false

        def allocatedServers = []

        4.times{mockEc2Server.demand.getAvailabilityZone { -> "newyork" }}

        1.times {
            mockEc2.demand.newServers {numberOfServers, instanceType, params ->
                // assertEquals 1, numberOfServers
                assertEquals EC2InstanceType.SMALL, instanceType
                assertEquals ([:], params)
                if (numberOfServers < 1)
                    return []
                def servers = (1..numberOfServers).collect {new EC2Server()}
                allocatedServers.addAll(servers)
                servers
            }
        }
       4.times {
            mockEc2.demand.newServers {numberOfServers, instanceType, params ->
                // assertEquals 1, numberOfServers
                assertEquals EC2InstanceType.SMALL, instanceType
                assertEquals (["Placement.AvailabilityZone": "newyork"], params)
                if (numberOfServers < 1)
                    return []
                def servers = (1..numberOfServers).collect {new EC2Server()}
                allocatedServers.addAll(servers)
                servers
            }
        }


        mockEc2Server.use {
            mockEc2.use {
                def ec2 = new EC2(awsProperties)

                def topology = new MultipleInstancesTopology()

                ClusterHosts servers = topology.allocateServers(ec2, clusterSpec, false)

                assertEquals allocatedServers[0], servers.databaseServer
                assertEquals allocatedServers[1..1], servers.mySqlSlaves
                assertEquals allocatedServers[2..2], servers.tomcats
                assertEquals allocatedServers[3], servers.apacheServer
                assertNull servers.jmeter
                assertEquals 4, allocatedServers.size()
            }
        }
    }

    public void testAllocateServersWithHaSlave() {

        clusterSpec.haSlave()
        clusterSpec.withSecurityGroupPrefix("foo")
        
        def allocatedServers = []

        mockEc2Server.demand.getAvailabilityZone { -> "newyork" }
        mockEc2Server.demand.getAvailabilityZone { -> "newyork" }
        mockEc2Server.demand.getAvailabilityZone { -> "newyork" }
        mockEc2Server.demand.getAvailabilityZone { -> "newyork" }
        mockEc2Server.demand.getAvailabilityZone { -> "newyork" }

        1.times {
            mockEc2.demand.newServers {numberOfServers, instanceType, params ->
                // assertEquals 1, numberOfServers
                assertEquals EC2InstanceType.SMALL, instanceType
                if (numberOfServers < 1)
                    return []
                def servers = (1..numberOfServers).collect {new EC2Server()}
                allocatedServers.addAll(servers)
                servers
            }
        }

        mockEc2.demand.newServersElsewhere {numberOfServers, instanceType, otherServer, params ->
            // assertEquals 1, numberOfServers
            assertEquals EC2InstanceType.SMALL, instanceType
            assertEquals 1, numberOfServers
            assertEquals allocatedServers[0], otherServer
            assertEquals (["SecurityGroup.1" : "foo-dbslaves"], params)
            def servers = (1..numberOfServers).collect {new EC2Server()}
            allocatedServers.addAll(servers)
            servers
        }

        5.times {
            mockEc2.demand.newServers {numberOfServers, instanceType, params ->
                // assertEquals 1, numberOfServers
                assertEquals EC2InstanceType.SMALL, instanceType
                if (numberOfServers < 1)
                    return []
                def servers = (1..numberOfServers).collect {new EC2Server()}
                allocatedServers.addAll(servers)
                servers
            }
        }

        mockEc2Server.use {
            mockEc2.use {
                def ec2 = new EC2(awsProperties)

                def topology = new MultipleInstancesTopology()

                ClusterHosts servers = topology.allocateServers(ec2, clusterSpec, false)

                assertEquals allocatedServers[0], servers.databaseServer
                assertEquals allocatedServers[1..1], servers.mySqlSlaves
                assertEquals allocatedServers[2..2], servers.tomcats
                assertEquals allocatedServers[3], servers.apacheServer
                assertEquals allocatedServers[4], servers.jmeter

            }
        }
        assertEquals 5, allocatedServers.size()
    }

    public void testAllocateServersWithEbsVolume() {

        def allocatedServers = []
        clusterSpec.withExistingEbsVolume("vol-123434", "q")

        mockEc2.demand.getAvailabilityZoneOfEbsVolume { "hong-kong" }
        
        mockEc2Server.demand.getAvailabilityZone { -> "newyork" }
        mockEc2Server.demand.getAvailabilityZone { -> "newyork" }
        mockEc2Server.demand.getAvailabilityZone { -> "newyork" }
        mockEc2Server.demand.getAvailabilityZone { -> "newyork" }
        mockEc2Server.demand.getAvailabilityZone { -> "newyork" }

        mockEc2.demand.newServers {numberOfServers, instanceType, params ->
                // assertEquals 1, numberOfServers
                assertEquals EC2InstanceType.SMALL, instanceType
                assertEquals(["Placement.AvailabilityZone" : "hong-kong"], params)
                if (numberOfServers < 1)
                    return []
                def servers = (1..numberOfServers).collect {new EC2Server()}
                allocatedServers.addAll(servers)
                servers
            }

        5.times {
            mockEc2.demand.newServers {numberOfServers, instanceType, params ->
                // assertEquals 1, numberOfServers
                assertEquals EC2InstanceType.SMALL, instanceType
                assertEquals (["Placement.AvailabilityZone": "newyork"], params)
                if (numberOfServers < 1)
                    return []
                def servers = (1..numberOfServers).collect {new EC2Server()}
                allocatedServers.addAll(servers)
                servers
            }
        }


        mockEc2Server.use {
            mockEc2.use {
                def ec2 = new EC2(awsProperties)

                def topology = new MultipleInstancesTopology()

                ClusterHosts servers = topology.allocateServers(ec2, clusterSpec, false)

                assertEquals allocatedServers[0], servers.databaseServer
                assertEquals allocatedServers[1..1], servers.mySqlSlaves
                assertEquals allocatedServers[2..2], servers.tomcats
                assertEquals allocatedServers[3], servers.apacheServer
                assertEquals allocatedServers[4], servers.jmeter

            }
        }
        assertEquals 5, allocatedServers.size()
    }


}